import { extend } from "jquery"

namespace study4_03 {

    // in 关键字

    // 一、类型层面用于构造类型
    // 二、运行时用于判断对象属性是否存在

    // 类型层面的 in
    // 类型层面。in关键字用于构造映射类型。它允许我们基于一个对象类型的键的集合来创建新的类型。
    // 通常会与keyof一起使用


    // 1、简单的映射类型
    type Person = {
        name: string
        age: number
        isEmployed: boolean
    }

    type partialPerson = {
        [K in keyof Person]?: Person[K]
    }
    // partialPerson 的类型为
    // {
    //     name?: string | undefined;
    //     age?: number | undefined;
    //     isEmployed?: boolean | undefined;
    // }
    // 在这个例子中，PartialPerson 是基于 Person 类型的映射类型，它将 Person 中的每个键都变成了可选属性。



    // 2、映射类型与联合类型
    // 基于联合类型生产新类型


    type Keys = 'name' | 'age' | 'isEmployed'

    type Person3 = {
        [K in Keys]: string | number | string
    }

    // Person3 类型为:
    // {
    //     name: string | number | boolean;
    //     age: string | number | boolean;
    //     isEmployed: string | number | boolean;
    // }


    // 在这个例子中，Person 类型被构造成包含 "name", "age", 和 "isEmployed" 这三个键，
    // 每个键的类型是 string | number | boolean。


    // 3、条件类型中的 in
    // in 关键字还可以与条件类型结合使用，以创建更复杂的类型

    type MessageOf<T> = T extends { message: unknown } ? T['message'] : never

    type Email = {
        message: string;
        from: string
    }

    type SMS = {
        message: string
        phoneNumber: string
    }

    type Chat = { content: string }

    type EmailMessageContents = MessageOf<Email> // string
    type SMSMessageContents = MessageOf<SMS> // string
    type ChatMessageContents = MessageOf<Chat>; // never

    // MessageOf类型根据 T 类型是否包含 message 属性来确定返回类型




    // 运行时的 in
    // 在运行时，in关键字用于检查对象中是否存在某个属性，返回布尔值。

    let person2 = {
        name: "Alice",
        age: 30
    };

    console.log('name' in person2); // true
    console.log('age' in person2); // true
    console.log('gender' in person2); // true

    // 这里，"name" in person 检查对象 person 是否具有 name 属性。



    // 实战案例

    // 1、条件类型结合 in ，
    // 用in来创建类型保护，从而在不同的代码路径中拥有不同的类型推断
    type Bird = {
        fly: () => void
    }
    type Fish = {
        swim(): void
    }
    function move(animal: Bird | Fish) {
        if ('fly' in animal) {
            animal.fly()
        } else {
            animal.swim()
        }
    }
    // 在这个例子中，in关键字帮助ts推断出animal的具体类型


    // 2、创建部分类型
    // 可以利用in 和 keyof 创建只包含某些属性的类型
    type Pick<T, K extends keyof T> = {
        [P in K]: T[P]
    }
    type Person4 = {
        name: string
        age: number
        gender: string
    }

    type NameAndAge = Pick<Person, 'name' | 'age'>
    // NameAndAge 类型为 { name: string; age: number; }

    // Pick是ts中内置的一个常用的工具类型，它利用in和keyof来构造部分类型

    // 总结
    // 1、类型层面的in：常用于构造映射类型，将对象的键映射到新的类型或者属性上，特别是在动态生成对象类型时非常有利
    // 2、运行时的in：用于检查对象中是否存在某个属性，在条件判断和类型保护中十分常见
    // 3、实战应用：in在类型系统中提供了极大的灵活性，使得我们可以动态生成类型结构，并且在运行时用于检查属性存在性，帮助类型推断
    // 4、通过灵活运用in，你可以在ts中编写出更具表达力和类型安全的代码



}